#include "file_copy.h"

// 全局变量定义
const char* g_src_file = NULL;
const char* g_dst_file = NULL;
long g_file_size = 0;
int g_shmid = -1;

// 信号处理（拷贝完成）
void signal_handler(int signum) {
    if (signum == SIGUSR1) {
        printf("\n[成功] 文件拷贝完成！\n");
        shmctl(g_shmid, IPC_RMID, NULL);  // 清理共享内存
        exit(EXIT_SUCCESS);
    }
}

// 交互控制（父进程）
void ui_handler(pid_t pid) {
    int op;
    int copy_state = 1;  // 1-运行中，2-暂停
    signal(SIGUSR1, signal_handler);

    printf("\n===== 拷贝控制 =====");
    printf("\n1. 暂停/继续");
    printf("\n2. 查看进度");
    printf("\n3. 终止拷贝");
    printf("\n====================\n");

    while (1) {
        printf("\n操作: ");
        if (scanf("%d", &op) != 1) {
            op = -1;
            while (getchar() != '\n');
        }

        switch (op) {
            case 1:
                if (copy_state == 1) {
                    kill(pid, SIGSTOP);
                    printf("已暂停\n");
                    copy_state = 2;
                } else {
                    kill(pid, SIGCONT);
                    printf("已继续\n");
                    copy_state = 1;
                }
                break;
            case 2: {
                void* p = shmat(g_shmid, NULL, 0);
                if (p != (void*)-1) {
                    printf("当前进度: %d%%\n", *(int*)p);
                    shmdt(p);
                }
                break;
            }
            case 3:
                kill(pid, SIGTERM);
                unlink(g_dst_file);  // 删除未完成文件
                printf("已终止，清理完成\n");
                shmctl(g_shmid, IPC_RMID, NULL);
                exit(EXIT_SUCCESS);
            default:
                printf("无效操作\n");
        }
    }
}

// 实际拷贝逻辑（子进程）
void copy_file() {
    int fd_src = open(g_src_file, O_RDONLY);
    int fd_dst = open(g_dst_file, O_WRONLY);
    if (fd_src == -1 || fd_dst == -1) {
        perror("文件打开失败");
        exit(EXIT_FAILURE);
    }

    char buff[BUFFER_SIZE];
    int ret;
    long copy_cnt = 0;
    void* shm_ptr = shmat(g_shmid, NULL, 0);
    if (shm_ptr == (void*)-1) {
        perror("共享内存连接失败");
        exit(EXIT_FAILURE);
    }

    // 循环拷贝并更新进度
    while ((ret = read(fd_src, buff, sizeof(buff))) > 0) {
        write(fd_dst, buff, ret);
        copy_cnt += ret;
        *(int*)shm_ptr = (int)((100.0 * copy_cnt) / g_file_size);
    }

    // 清理资源
    shmdt(shm_ptr);
    close(fd_src);
    close(fd_dst);
    kill(getppid(), SIGUSR1);  // 通知父进程完成
    exit(EXIT_SUCCESS);
}

// 拷贝模块入口（必须实现，否则main.c会报undefined）
void file_copy_menu() {
    char src[256], dst[256];
    struct stat st;

    printf("\n===== 文件拷贝 =====");
    printf("\n源文件路径: ");
    scanf("%s", src);
    printf("目标文件路径: ");
    scanf("%s", dst);

    // 校验源文件
    if (access(src, R_OK) == -1) {
        perror("源文件不可读");
        return;
    }
    if (lstat(src, &st) == -1) {
        perror("获取文件信息失败");
        return;
    }
    g_file_size = st.st_size;
    g_src_file = src;
    g_dst_file = dst;

    // 创建目标文件
    int fd_dst = creat(dst, st.st_mode);
    if (fd_dst == -1) {
        perror("创建目标文件失败");
        return;
    }
    close(fd_dst);

    // 创建共享内存
    g_shmid = shmget(IPC_PRIVATE, SHARED_MEM_SIZE, IPC_CREAT | 0644);
    if (g_shmid == -1) {
        perror("共享内存创建失败");
        unlink(dst);
        return;
    }

    // 创建子进程
    pid_t pid = fork();
    if (pid == -1) {
        perror("创建进程失败");
        unlink(dst);
        shmctl(g_shmid, IPC_RMID, NULL);
        return;
    } else if (pid > 0) {
        ui_handler(pid);  // 父进程控制
    } else {
        copy_file();      // 子进程拷贝
    }
}
